with Ada.Streams; use Ada.Streams;
with Ada.Streams.Stream_IO;
with Ada.Strings.Fixed; 
with Ada.Directories;
package body Text_Builder is


   procedure Set_TAB (
      this : in out Builder_Type;
      Tab  : String := Default_Tab
      ) 
   is
   begin
      Set_Unbounded_String(this.Tab, Tab);
   end Set_Tab;

   procedure Set_Linefeed (
      this : in out Builder_Type;
      Linefeed : String := Default_Linefeed
      )
   is
   begin
      Set_Unbounded_String(this.Linefeed, Linefeed);
   end Set_Linefeed;

   procedure Set_Line_Number_Width (
      this : in out Builder_Type;
      Width : Natural := 0
      )
   is
   begin
      this.Line_Number_Width := Width;
   end Set_Line_Number_Width;

   procedure Append (
      this : in out Builder_Type;
      S : String
      )
   is
   begin
      Append(this.Data, S);
   end Append;

   procedure Append_Line (
      this       : in out Builder_Type;
      S          : String := "";
      New_Indent : Indent_Direction := ID_None 
      )
   is
   begin
      this.Append(S);
      case New_Indent is
         when ID_Inc => this.Inc_Indent;
         when ID_Dec => this.Dec_Indent;
         when others => null;
      end case;
      this.New_Line;
   end Append_Line;

   procedure Reset (
      this : in out Builder_Type;
      Style : Format_Style := fs_Manual
      )
   is
   begin
      case Style is
         when fs_Compact =>
            this.Set_TAB("");
            this.Set_Linefeed("");
            this.Set_Line_Number_Width(0);
         when fs_Normal =>
            this.Set_TAB(Default_Tab);
            this.Set_Linefeed(Default_Linefeed);
            this.Set_Line_Number_Width(0);
         when fs_Source =>
            this.Set_TAB(Default_Tab);
            this.Set_Linefeed(Default_Linefeed);
            this.Set_Line_Number_Width(5);
         when others =>
            null;
      end case;
      this.Clear;
   end Reset;

   procedure Clear (this : in out Builder_Type)
   is
   begin
      this.Line_Number := 1;
      Set_Unbounded_String(this.Data, "");
      this.Append_Line_Number;
      this.Append_Tab;
   end Clear;

   procedure Append_Line_Number (this : in out Builder_Type)
   is
   begin
      if this.Line_Number_Width > 0 then
         Append(
            this.Data, 
            Fixed.Tail(
               Source  => Natural'Image(this.Line_Number),
               Count   => this.Line_Number_Width,
               Pad     => ' '
            ) & " "
         );
      end if;
   end Append_Line_Number;

   procedure Append_Tab (this : in out Builder_Type)
   is
   begin
      if Length(this.Tab) > 0 then
         for i in 1..this.Indent loop
            Append(this.Data, this.Tab);
         end loop;
      end if;
   end Append_Tab;

   procedure New_Line (this : in out Builder_Type)
   is
   begin
      Append(this.Data, this.Linefeed);
      this.Line_Number := this.Line_Number + 1;
      this.Append_Line_Number;
      this.Append_Tab;
   end New_Line;

   procedure Inc_Indent (this : in out Builder_Type)
   is
   begin
      this.Indent := this.Indent + 1;
   end Inc_Indent;

   procedure Dec_Indent (this : in out Builder_Type)
   is
   begin
      if this.Indent > 0 then
         this.Indent := this.Indent - 1;
      end if;
   end Dec_Indent;

   procedure Save_To_File (
      this : in out Builder_Type'Class;
      Filename : String
      )
   is
      File : Stream_IO.File_Type;
   begin
      Stream_IO.Create(File => File, Name => Filename);
      String'Write(Stream_IO.Stream(File), this.To_String);
      Stream_IO.Close(File);
   end Save_To_File;

   procedure Append_To_File (
      this : in out Builder_Type'Class;
      Filename : String
      )
   is
      File : Stream_IO.File_Type;
   begin
      if Ada.Directories.Exists(Filename) then
         Stream_IO.Open(File, Name => Filename, Mode => Stream_IO.Append_File);
      else
         Stream_IO.Create(File => File, Name => Filename);
      end if;
      String'Write(Stream_IO.Stream(File), this.To_String);
      Stream_IO.Close(File);
   end Append_To_File;

   function To_String (
      this : Builder_Type
      ) return String
   is
   begin
      return To_String(this.Data);
   end To_String;


end Text_Builder;
